<?php

namespace App\Jobs;

use App\Models\BillExport;
use App\Models\MoneyTransaction;
use EasyWeChat\OfficialAccount\Application;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Log;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use PhpOffice\PhpSpreadsheet\Writer\Csv;
use Dompdf\Dompdf;
use Dompdf\Options;
use EasyWeChat\Factory;

class ProcessBillExportJob implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    protected $export;

    /**
     * Create a new job instance.
     */
    public function __construct(BillExport $export)
    {
        $this->export = $export;
    }

    /**
     * Execute the job.
     */
    public function handle(): void
    {
        try {
            // 更新状态为处理中
            $this->export->update(['status' => 'processing']);

            // 获取交易数据
            $transactions = $this->getTransactions();

            if ($transactions->isEmpty()) {
                throw new \Exception('没有找到符合条件的交易记录');
            }

            // 根据格式生成文件
            $filePath = $this->generateFile($transactions);

            // 更新导出记录
            $this->export->update([
                'status' => 'completed',
                'file_path' => $filePath,
            ]);

            // 发送微信通知
            $this->sendWechatNotification();

            Log::info('账单导出完成', ['export_id' => $this->export->id]);

        } catch (\Exception $e) {
            // 更新状态为失败
            $this->export->update([
                'status' => 'failed',
                'error_message' => $e->getMessage(),
            ]);

            Log::error('账单导出失败', [
                'export_id' => $this->export->id,
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString()
            ]);

            throw $e;
        }
    }

    /**
     * 获取交易数据
     */
    private function getTransactions()
    {
        $query = MoneyTransaction::where('book_id', $this->export->book_id)
            ->with(['category', 'subCategory', 'user'])
            ->orderBy('transaction_date', 'desc')
            ->orderBy('created_at', 'desc');

        // 根据导出范围筛选
        switch ($this->export->export_range) {
            case 'month':
                $query->whereMonth('transaction_date', now()->month)
                      ->whereYear('transaction_date', now()->year);
                break;
            case 'custom':
                if ($this->export->start_date && $this->export->end_date) {
                    $query->whereBetween('transaction_date', [
                        $this->export->start_date,
                        $this->export->end_date
                    ]);
                }
                break;
            // 'all' 不需要额外筛选
        }

        return $query->get();
    }

    /**
     * 生成文件
     */
    private function generateFile($transactions)
    {
        $filename = 'exports/' . date('Ym') . '/' . $this->export->id . '_' . time();

        switch ($this->export->format) {
            case 'excel':
                return $this->generateExcel($transactions, $filename . '.xlsx');
            case 'csv':
                return $this->generateCsv($transactions, $filename . '.csv');
            case 'pdf':
                return $this->generatePdf($transactions, $filename . '.pdf');
            default:
                throw new \Exception('不支持的导出格式');
        }
    }

    /**
     * 生成Excel文件
     */
    private function generateExcel($transactions, $filename)
    {
        $spreadsheet = new Spreadsheet();
        $sheet = $spreadsheet->getActiveSheet();

        // 设置表头
        $headers = ['日期', '类型', '金额', '分类', '子分类', '备注', '记录人', '创建时间'];
        $sheet->fromArray($headers, null, 'A1');

        // 设置表头样式
        $headerStyle = [
            'font' => ['bold' => true],
            'fill' => [
                'fillType' => \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID,
                'startColor' => ['rgb' => 'E6E6FA']
            ]
        ];
        $sheet->getStyle('A1:H1')->applyFromArray($headerStyle);

        // 填充数据
        $row = 2;
        foreach ($transactions as $transaction) {
            $data = [
                $transaction->transaction_date->format('Y-m-d'),
                $transaction->type === 'income' ? '收入' : '支出',
                $transaction->amount,
                $transaction->category->name ?? '',
                $transaction->subCategory->name ?? '',
                $transaction->description ?? '',
                $transaction->user->nickname ?: $transaction->user->name,
                $transaction->created_at->format('Y-m-d H:i:s'),
            ];
            $sheet->fromArray($data, null, 'A' . $row);
            $row++;
        }

        // 自动调整列宽
        foreach (range('A', 'H') as $col) {
            $sheet->getColumnDimension($col)->setAutoSize(true);
        }

        // 保存文件
        $writer = new Xlsx($spreadsheet);
        $fullPath = Storage::disk('exports')->path($filename);

        // 确保目录存在
        $directory = dirname($fullPath);
        if (!is_dir($directory)) {
            mkdir($directory, 0755, true);
        }

        $writer->save($fullPath);

        return $filename;
    }

    /**
     * 生成CSV文件
     */
    private function generateCsv($transactions, $filename)
    {
        $fullPath = Storage::disk('exports')->path($filename);

        // 确保目录存在
        $directory = dirname($fullPath);
        if (!is_dir($directory)) {
            mkdir($directory, 0755, true);
        }

        $file = fopen($fullPath, 'w');

        // 添加BOM以支持中文
        fwrite($file, "\xEF\xBB\xBF");

        // 写入表头
        $headers = ['日期', '类型', '金额', '分类', '子分类', '备注', '记录人', '创建时间'];
        fputcsv($file, $headers);

        // 写入数据
        foreach ($transactions as $transaction) {
            $data = [
                $transaction->transaction_date->format('Y-m-d'),
                $transaction->type === 'income' ? '收入' : '支出',
                $transaction->amount,
                $transaction->category->name ?? '',
                $transaction->subCategory->name ?? '',
                $transaction->description ?? '',
                $transaction->user->nickname ?: $transaction->user->name,
                $transaction->created_at->format('Y-m-d H:i:s'),
            ];
            fputcsv($file, $data);
        }

        fclose($file);

        return $filename;
    }

    /**
     * 生成PDF文件
     */
    private function generatePdf($transactions, $filename)
    {
        $options = new Options();
        $options->set('defaultFont', 'DejaVu Sans');
        $options->set('isHtml5ParserEnabled', true);
        $options->set('isPhpEnabled', true);
        $options->set('chroot', realpath(base_path()));
        $options->set('fontDir', storage_path('fonts'));
        $options->set('fontCache', storage_path('fonts'));
        $options->set('tempDir', storage_path('app/temp'));
        $options->set('isRemoteEnabled', true);
        $options->set('defaultMediaType', 'screen');
        $options->set('isFontSubsettingEnabled', true);

        $dompdf = new Dompdf($options);

        // 生成HTML内容
        $html = $this->generatePdfHtml($transactions);

        $dompdf->loadHtml($html);
        $dompdf->setPaper('A4', 'portrait');
        $dompdf->render();

        $fullPath = Storage::disk('exports')->path($filename);

        // 确保目录存在
        $directory = dirname($fullPath);
        if (!is_dir($directory)) {
            mkdir($directory, 0755, true);
        }

        file_put_contents($fullPath, $dompdf->output());

        return $filename;
    }

    /**
     * 生成PDF的HTML内容
     */
    private function generatePdfHtml($transactions)
    {
        $html = '
        <!DOCTYPE html>
        <html>
        <head>
            <meta charset="UTF-8">
            <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
            <style>
                body {
                    font-family: "DejaVu Sans", sans-serif;
                    font-size: 12px;
                    line-height: 1.4;
                }
                .header { text-align: center; margin-bottom: 20px; }
                .title { font-size: 18px; font-weight: bold; margin-bottom: 10px; }
                .info { margin: 5px 0; }
                table {
                    width: 100%;
                    border-collapse: collapse;
                    margin-top: 20px;
                    font-size: 11px;
                }
                th, td {
                    border: 1px solid #ddd;
                    padding: 6px;
                    text-align: left;
                    word-wrap: break-word;
                }
                th {
                    background-color: #f2f2f2;
                    font-weight: bold;
                    text-align: center;
                }
                .amount-income { color: #28a745; font-weight: bold; }
                .amount-expense { color: #dc3545; font-weight: bold; }
                .footer {
                    margin-top: 20px;
                    text-align: center;
                    font-size: 10px;
                    color: #666;
                }
                .text-center { text-align: center; }
                .text-right { text-align: right; }
            </style>
        </head>
        <body>
            <div class="header">
                <div class="title">' . htmlspecialchars($this->export->title, ENT_QUOTES, 'UTF-8') . '</div>
                <div class="info">&#36134;&#26412;&#65306;' . htmlspecialchars($this->export->book->name, ENT_QUOTES, 'UTF-8') . '</div>
                <div class="info">&#23548;&#20986;&#26102;&#38388;&#65306;' . now()->format('Y-m-d H:i:s') . '</div>
            </div>

            <table>
                <thead>
                    <tr>
                        <th>&#26085;&#26399;</th>
                        <th>&#31867;&#22411;</th>
                        <th>&#37329;&#39069;</th>
                        <th>&#20998;&#31867;</th>
                        <th>&#23376;&#20998;&#31867;</th>
                        <th>&#22791;&#27880;</th>
                        <th>&#35760;&#24405;&#20154;</th>
                    </tr>
                </thead>
                <tbody>';

        foreach ($transactions as $transaction) {
            $amountClass = $transaction->type === 'income' ? 'amount-income' : 'amount-expense';
            $typeText = $transaction->type === 'income' ? '&#25910;&#20837;' : '&#25903;&#20986;';

            $html .= '
                    <tr>
                        <td>' . $transaction->transaction_date->format('Y-m-d') . '</td>
                        <td>' . $typeText . '</td>
                        <td class="' . $amountClass . '">' . number_format($transaction->amount, 2) . '</td>
                        <td>' . htmlspecialchars($transaction->category->name ?? '', ENT_QUOTES, 'UTF-8') . '</td>
                        <td>' . htmlspecialchars($transaction->subCategory->name ?? '', ENT_QUOTES, 'UTF-8') . '</td>
                        <td>' . htmlspecialchars($transaction->description ?? '', ENT_QUOTES, 'UTF-8') . '</td>
                        <td>' . htmlspecialchars($transaction->user->nickname ?: $transaction->user->name, ENT_QUOTES, 'UTF-8') . '</td>
                    </tr>';
        }

        $html .= '
                </tbody>
            </table>

            <div class="footer">
                <p>&#35760;&#36134;&#21161;&#25163; - &#35753;&#35760;&#36134;&#26356;&#31616;&#21333;</p>
            </div>
        </body>
        </html>';

        return $html;
    }

    /**
     * 发送微信通知
     */
    private function sendWechatNotification()
    {
        try {
            $user = $this->export->user;


            if (!$user->openid) {
                Log::info('用户未绑定微信，跳过通知', ['user_id' => $user->id]);
                return;
            }

            // 生成公开下载链接
            $downloadUrl = $this->export->getPublicDownloadUrl();
            
            $message = "您的账单导出已完成！\n\n" .
                      "导出内容：{$this->export->title}\n" .
                      "导出格式：{$this->export->getFormatText()}\n" .
                      "有效期：3天\n\n";
            
            if ($downloadUrl) {
                $message .= "点击下载：{$downloadUrl}\n\n" .
                           "提示：如无法直接下载，请复制链接到浏览器打开。";
            } else {
                $message .= "请登录记账助手下载文件。";
            }

            $this->sendCustomerServiceMessage($message, $user->openid);

            Log::info('微信通知发送成功', ['user_id' => $user->id, 'export_id' => $this->export->id, 'download_url' => $downloadUrl]);

        } catch (\Exception $e) {
            Log::error('微信通知发送失败', [
                'user_id' => $this->export->user_id,
                'export_id' => $this->export->id,
                'error' => $e->getMessage()
            ]);
        }
    }

    private function sendCustomerServiceMessage($content, $openid)
    {
        try {
            $app = new Application(config('wechat.official_account.default'));
            $client = $app->getClient();
            $response = $client->postJson('/cgi-bin/message/custom/send', [
                "touser" => $openid,
                "msgtype" => "text",
                "text" => [
                    "content" => $content
                ]
            ]);
            $res_str = $response->getContent();
            $res = json_decode($res_str, true);
            if ($res['errcode'] != 0) {
                Log::error('发送客服消息失败：' . $res_str);
            }
//            log_record($res);
        } catch (\Exception $e) {
            Log::error('发送客服消息失败：' . exception_to_string($e));
        }
    }

    /**
     * Handle a job failure.
     */
    public function failed(\Throwable $exception): void
    {
        $this->export->update([
            'status' => 'failed',
            'error_message' => $exception->getMessage(),
        ]);

        Log::error('账单导出任务失败', [
            'export_id' => $this->export->id,
            'error' => $exception->getMessage(),
            'trace' => $exception->getTraceAsString()
        ]);
    }
}
